function DataModel() {

    this.$list = [];
    this.__deps = null;
}



yaxi.DataModel = Object.extend(function (base) {




    function $Submodel(name) {
    
        var Class = this;

        return {

            get: function () {

                var subs = this.__subs || (this.__subs = {});
                return subs[name] || (subs[name] = new Class());
            },

            set: function (value) {

                var subs = this.__subs;
                var instance = subs && subs[name];

                if (value && value.length > 0)
                {
                    if (!instance)
                    {
                        instance = (subs || (this.__subs = {}))[name] = new Class();
                    }

                    instance.load(value);
                }
                else if (instance)
                {
                    instance.clear();
                }
            }
        };
    }


    // 初始化类
    (function init(Class) {

        Class.init = init;

        // 作为子模型属性
        Class.$Submodel = $Submodel;

    })(DataModel);



    // 子项数量(只读)
    $define(this, 'length', {

        get: function () {

            return this.$list.length;
        },

        set: function (value) {

            throwTextError('datasheet length is readonly!');
        }
    });



    // 可订阅标记(for检测用)
    this.$subscribable = true;


    // state标记(创建state属性值时检测用)
    this.__fields = true;




    this.indexOf = function (searchElement, fromIndex) {

        return wrapValue(this, 'indexOf', arguments);
    }

    
    this.lastIndexOf = function (searchElement, fromIndex) {

        return wrapValue(this, 'lastIndexOf', arguments);
    }


    this.every = function (fn, thisArg) {

        return wrapValue(this, 'every', arguments);
    }


    this.some = function (fn, thisArg) {

        return wrapValue(this, 'some', arguments);
    }


    this.find = function (fn, thisArg) {

        return wrapValue(this, 'find', arguments);
    }


    this.findIndex = function (fn, thisArg) {

        return wrapValue(this, 'findIndex', arguments);
    }


    this.join = function (separator) {

        return wrapValue(this, 'join', arguments);
    }


    this.includes = function (valueToFind, fromIndex) {

        return wrapValue(this, 'includes', arguments);
    }


    this.reduce = function (fn, initialValue) {

        return wrapValue(this, 'reduce', arguments);
    }


    this.reduceRight = function (fn, initialValue) {

        return wrapValue(this, 'reduceRight', arguments);
    }



    this.forEach = function (fn, thisArg) {

        this.$list.forEach(fn, thisArg);
    }



    this.filter = function (fn, thisArg) {

        return wrapList(this, 'filter', arguments);
    }


    this.map = function (fn, thisArg) {

        return wrapList(this, 'map', arguments);
    }




    function wrapList(observeList, method, args) {

        var result = new DataModel();
        var list = result.$list;

        result.__deps = observeList.__deps;
        result.__watch = watch;
        result.__unwatch = unwatch;

        list.push.apply(list, list[method].apply(observeList.$list, args));

        return result;
    }


    function wrapValue(observeList, method, args) {

        var list = observeList.$list;

        if (bindingTarget)
        {
            watch(observeList, bindingTarget);
        }

        return list[method].apply(list, args);
    }



    function destroy(items) {

        var item, fn;

        for (var i = items.length; i--;)
        {
            if ((item = items[i]) && (fn = item.__destroy))
            {
                fn.call(item);
            }
        }
    }



    // 加载
    this.load = function (items) {

        var list = this.$list;

        if (list.length > 0)
        {
            destroy(list);
            list.length = 0;
        }

        if (items && items.length > 0)
        {
            list.push.apply(list, items);
        }

        notify(this, 'load', list);
        return this;
    }


    this.at = function (index) {

        if (bindingTarget)
        {
            watch(this, bindingTarget);
        }

        return this.$list[index];
    }


    this.append = function (item) {

        this.$list.push(item);
        notify(this, 'insert', -1, item);
    }


    this.insert = function (index, item) {

        var list = this.$list;
        var length = list.length;

        if ((index |= 0) < 0 && (index += length) < 0)
        {
            index = 0;
        }
        else if (index > length)
        {
            index = length;
        }

        list.splice(index, 0, item);
        notify(this, 'insert', index, item);
    }


    this.replace = function (index, item) {

        var list = this.$list;
        var oldItem, fn;

        if ((index |= 0) < 0)
        {
            index += list.length;
        }

        if (list.length > index)
        {
            if ((oldItem = list[index]) && (fn = oldItem.__destroy))
            {
                fn.call(oldItem);
            }

            notify(this, 'set', index, list[index] = item);
        }
    }


    this.removeAt = function (index) {

        var list = this.$list;
        var length = list.length;
        var removed, fn;

        if ((index |= 0) < 0 && (index += length) < 0)
        {
            index = 0;
        }
        else if (index >= length)
        {
            return;
        }

        removed = list.splice(index, 1);

        if (removed.length > 0)
        {
            if ((removed = removed[0]) && (fn = removed.__destroy))
            {
                fn.call(removed);
            }

            notify(this, 'remove', index);
        }
    }


    this.remove = function (item) {

        var list = this.$list;
        var index = list.indexOf(item);
        var fn;

        if (index >= 0)
        {
            removed = list.splice(index, 1);

            if ((removed = removed[0]) && (fn = removed.__destroy))
            {
                fn.call(removed);
            }

            notify(this, 'remove', index);
        }
    }


    this.clear = function () {

        var list = this.$list;

        if (list.length > 0)
        {
            destroy(list);

            list.splice(0);
            notify(this, 'clear');
        }
    }



    this.sort = function (sortFn) {

        this.$list.sort(sortFn);
        notify(this, 'sort', this);
    }


    this.reverse = function () {

        this.$list.reverse();
        notify(this, 'reverse');
    }



    function watch(observeList, subscriber) {

        var dependences;

        if (subscriber.name === '*')
        {
            subscriber.name = '';
        }

        if (dependences = observeList.__deps)
        {
            dependences.push(subscriber);
            return dependences;
        }

        return observeList.__deps = [subscriber];
    }


    function unwatch(observeList, dependences, subscriber) {

        for (var i = dependences.length; i--;)
        {
            if (dependences[i] === subscriber)
            {
                dependences.splice(i, 1);

                if (dependences.length <= 0)
                {
                    observeList.__deps = null;
                }

                break;
            }
        }
    }



    function notify(target, type, arg1, arg2) {
        
        var dependences, subscriber;

        if (dependences = target.__deps)
        {
            for (var i = 0, l = dependences.length; i < l; i++)
            {
                if ((subscriber = dependences[i]) && (!subscriber.name || subscriber.name === type))
                {
                    subscriber.$onchange(type, arg1, arg2);
                }
            }
        }
    }





    // 观察变化(内部用)
    this.__watch = watch;


    // 取消观察变化(内部用)
    this.__unwatch = unwatch;




    this.destroy = this.__destroy = function () {

        var list = this.$list;

        if (list.length > 0)
        {
            destroy(list);
            list.length = 0;
        }

        this.__deps = null;
    }



}, DataModel);

